

#include <fs.hpp>
#include <log.hpp>
#include <dynamic_buffer.hpp>
#include <boost/pool/pool_alloc.hpp>
using namespace xbase;

#include <iostream>

using namespace std;

using namespace boost::asio;

int main(int argc, char **argv)
{
	if(argc != 2)
	{
		cout << argv[0] << " <oldlog_file>" << endl;
		return -1;
	}

	fs::init("../../conf/gfsclient.conf");

	fs::file_t file = fs::open(std::string(argv[1]));
	if(file == fs::BAD_FILE)
	{
		cout << "open file error" << endl;
		return -1;
	}

	static const std::size_t min_bytes = 1024 * 1024;
	basic_simple_buffer<boost::pool_allocator<char> > file_buffer;
	file_buffer.prepare(0);
	file_buffer.prepare(1);
	file_buffer.prepare(0);
	file_buffer.prepare(min_bytes);
	file_buffer.prepare(0);
	file_buffer.prepare(1);
	file_buffer.prepare(0);

	std::size_t total_bytes = 0;
	std::size_t read_times = 0;
	std::size_t entry_count = 0;

	bool is_eof = false;
	do {
		for(;;) {
			const std::size_t need_bytes = check_buffer_for_log_entry(file_buffer.data());
			if(need_bytes > 0)		// not enough
			{
				if(is_eof)
				{
					if(file_buffer.size() > 0)
					{
						cout << "last entry not complete, ignore it(has "
						     << file_buffer.size() << " bytes, need "
						     << need_bytes << " bytes)" << endl;
						file_buffer.clear(); // clear it
					}
					// 正好处理完
					break;
				}

				const std::size_t space = file_buffer.max_size() - file_buffer.size();
				const std::size_t read_bytes = (std::max)(need_bytes, space);
				
				const fs::ssize_t len = fs::readn(file, file_buffer.prepare(read_bytes));
				if(len < 0) // error
				{
					cout << "read file error" << endl;
					return -1;
				}
				else if(static_cast<std::size_t>(len) < read_bytes)
				{
					cout << "eof: readed len " << len
					     << " less then " << read_bytes << endl;
					is_eof = true;
				}
				file_buffer.commit(len);
				total_bytes += len;
				++read_times;
			}
			else
			{
				break; // enough
			}
		}

		if(file_buffer.size() == 0) 
		{
			cout << "end: file_buffer size is 0" << endl;
			break;
		}

		// deal with this log entry
		const log_entry_wrapper *entry = wrapper_cast<const log_entry_wrapper *>(file_buffer.data());
		file_buffer.consume(entry->bytes());

		// cout << entry->to_string() << endl;

		file_buffer.prepare(0);
		file_buffer.prepare(1);
		file_buffer.prepare(0);

		++ entry_count;
	} while((! is_eof)
		|| (file_buffer.size() > 0));

	cout << "totally " << entry_count << " entries, readed "
	     << total_bytes << " bytes with "
	     << read_times << " times" << endl;

	return 0;
}
